package com.lzh.match.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

@Component
public class MatchingPool extends Thread {
    private static List<Player> players = new ArrayList<Player>();
    private static RestTemplate restTemplate;
    private ReentrantLock lock = new ReentrantLock();

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        MatchingPool.restTemplate = restTemplate;
    }

    public void addPlayer(Integer userId, Integer rating) {
        lock.lock();
        try {
            players.add(new Player(userId, rating, 0));
        } finally {
            lock.unlock();
        }
    }

    public void removePlayer(Integer userId) {
        lock.lock();
        try {
            List<Player> newPlayers = new ArrayList<>();
            for (Player player : players) {
                if (!player.getUserId().equals(userId)) {
                    newPlayers.add(player);
                }
            }
            players = newPlayers;
        } finally {
            lock.unlock();
        }
    }

    private void increaseWaitingTime() {
        for (Player player : players) {
            player.setWaitingTime(player.getWaitingTime() + 1);
        }
    }

    private boolean checkMatched(Player a, Player b, Player c) {
        int maxRating = Math.max(a.getRating(), Math.max(b.getRating(), c.getRating()));
        int minRating = Math.min(a.getRating(), Math.min(b.getRating(), c.getRating()));
        int ratingDelta = maxRating - minRating;
        int minWaitingTime = Math.min(a.getWaitingTime(), b.getWaitingTime());
        return ratingDelta <= minWaitingTime * 10;
    }

    private void sendResult(Player a, Player b, Player c) {
        System.out.println("send result: " + a + " " + b + " " + c);
        System.out.println("sendResult: " + a + " " + b + " " + c);
        MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
        data.add("aId", a.getUserId().toString());
        data.add("bId", b.getUserId().toString());
        data.add("cId", c.getUserId().toString());
        restTemplate.postForObject("http://127.0.0.1:8080/api/start/game/", data, String.class);
    }

    private void matchPlayers() {
        System.out.println("match players: " + players.toString());
        boolean[] used = new boolean[players.size()];
        for (int i = 0; i < players.size(); i++) {
            if (used[i]) continue;
            for (int j = i + 1; j < players.size(); j++) {
                if (used[j]) continue;
                for (int k = j + 1; k < players.size(); k++) {
                    if (used[k]) continue;
                    Player a = players.get(i);
                    Player b = players.get(j);
                    Player c = players.get(k);

                    if (checkMatched(a, b, c)) {
                        used[i] = true;
                        used[j] = true;
                        used[k] = true;
                        sendResult(a, b, c);
                        break;
                    }
                }
            }
        }
        List<Player> newPlayers = new ArrayList<>();
        for (int i = 0; i < players.size(); i++) {
            if (!used[i]) {
                newPlayers.add(players.get(i));
            }
        }
        players = newPlayers;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
                lock.lock();
                try {
                    increaseWaitingTime();
                    matchPlayers();
                } finally {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
